/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.foment.data;
import java.io.Serializable;
import java.util.*;
import java.sql.*;
/**
 *
 * klasa koja predstavlja rezultat upita
 * attributes - niz atributa koji se javljaju u rezultatu upita
 * values -vektor hashmapa. Svaka hashmapa predstavlja jedan red podataka iz rezultata upita
 * posto se atributi ne ponavljaju, key u hashmapi je dobro definisan.
 * values je niz tj. vektor ovakvih mapa. tako da imamo celu tabelu :)
 *
 * NAPOMENA:
 *
 * SqlDataResultet, kada se koristi u okviru klase tabela, sluzice samo za brisanje, dodavanje i
 * pristup podacima u lokalu, tj. za samog klijenta, a u metodama gde se vrsi izmena podataka
 * posebno ce se vrsiti komunikacija sa serverom, tj. bazom
 *
 *
 *
 * URADITI:
 *
 * u updateDate, zavrsiti updatovanje datuma
 *
 *
 * @author dusan i aleksandar :)
 */
public class SqlDataResultSet implements Serializable
{


    public SqlDataResultSet() {
        // do nothing for now
    }

    // copy constructor
    public SqlDataResultSet(SqlDataResultSet sd) {

       ArrayList<String> sdal = sd.getAttributes();
       Vector<HashMap> vhmsd  = sd.getValues();

       try {
         currentRow = sd.getRow();
       } catch (SQLException se) {
         // do nothing
       }


       // copy attributes
       Iterator ie = sdal.iterator();

       while(ie.hasNext())
          attributes.add((String) ie.next());

       // copy values
       Enumeration e = vhmsd.elements();

       while (e.hasMoreElements())
           values.add((HashMap) e.nextElement());

    }


    // formira SqlData od rezultata upita. Prvo vidimo koji su atributi u rs-u.
    public SqlDataResultSet(ResultSet rs)
    {
        // iz spiska svih atributa, proveravamo da li postoji u resultsetu
        // ako ga ima, onda ga dodajemo u listu atributa koji je rezultat upita
        for (String s : DatabaseAttributes.allDBAttributes)
        {
            try
            {
                // ako ima kolone, vrednost je nebitna, znaci da je tu,
                //ako nema, emitovace se izuzetak.
                if (rs.findColumn(s) != 0)
                    attributes.add(s);
            }
            catch(SQLException e) {
                //System.err.println("SqlData() " + e.getMessage());
                continue;
            }
        }
        //System.out.println("SqlData: Finished adding attributes");
        
        // sad dodajemo red po red. Svaki red predstavlja hashmapu.
        try
        {
            while(rs.next())
            {
                HashMap hm = new HashMap();
                // za svaki atribut koji se javlja u rezultatu upita, 
                // dodajemo taj atribut i njegovu vrenodst u hashmapu
                for (String key : attributes)
                {
                    ResultSetMetaData rsmd = rs.getMetaData();
                    int clmType = rsmd.getColumnType(rs.findColumn(key));


                    // checks for sql column type and add it into hash map
                    /*
                        we must do check for EmployeeID column, because when we call max(EmployeeID) + 1 as EmployeeID
                     *  sql returns this as string result
                     */
                    if (java.sql.Types.INTEGER == clmType || java.sql.Types.SMALLINT == clmType || key.equals("EmployeeID")) {

                        int val = rs.getInt(key);
                        hm.put(key, new SqlInteger(val));
                        
                    } else if (java.sql.Types.DATE == clmType || java.sql.Types.TIMESTAMP == clmType) {

                        java.util.Date date = rs.getDate(key);
                        hm.put(key, date);
                    
                    } else {

                      // add string
                      String val = rs.getString(key);
                      hm.put(key, new SqlString(val));

                    }

                    //String val = rs.getString(key);
                    //System.out.println("Added: " + key + " " + val);
                    //hm.put(key, val);
                }
                // kad smo napunili mapu za jedan red, taj red dodajemo u vektor
                values.add(hm);
            }
        }
        catch(SQLException e) {
            //System.err.println("SQlData " + e.getMessage());
        }
    }
    
    public void print()
    {
        Enumeration e = values.elements();
        while (e.hasMoreElements())
        {
            HashMap hm = (HashMap)e.nextElement();
            Set keys = hm.keySet();
            Iterator i = keys.iterator();
            while(i.hasNext())
            {
                String tmp = (String)i.next();
                if (hm.containsKey(tmp))
                    System.out.print(tmp + " " + (String)hm.get(tmp) + " ");
            }
            System.out.println();
        }
    }

    // f-ja koja vraca vrednost atributa u datoj koloni. ili null, ako
    // atribut nije u spisku atributa
    public int getRowCount() { return values.size();}

    
    public String getValue(String attr, int row) {

        HashMap tmp = values.elementAt(row);
        if (tmp.containsKey(attr))
            return (String)tmp.get(attr);
        return null;
    }

    // temporary only, for testing purposes
    public String toString() {
      print();
      return "";
    }


    /* ----------------- IMPORTANT -------------------------
     * Implementation of methods that will act, just like in result set
     *
     * this is necessary to retain funcionallity of Table class

     */


    /*
       sets the cursor on first element and returns true
     * returns false if result set is empty

     */
    public boolean first() {

        if (values.size() == 0)
            return false;

        currentRow = 0;
        return true;
    }

    /* returns integer from the current row for AttributeName stated in the function argument */
    public int getInt(String attrName) throws SQLException {

        HashMap hm = values.get(currentRow);
        if (hm.containsKey(attrName))
           return ((SqlInteger) hm.get(attrName)).getValue();

        return -1;
    }

    /* updates integer from the current row for AttributeName stated in the function argument */
    public void updateInt(String attrName, int value) throws SQLException {

        HashMap hm = values.get(currentRow);

        if (hm.containsKey(attrName)) {

            //System.out.println("Setting: " + attrName + " " + value);
           ((SqlInteger) hm.get(attrName)).setValue(value);
        }

    }


    /* returns string from the current row for AttributeName stated in the function argument */
    public String getString(String attrName) throws SQLException {

        HashMap hm = values.get(currentRow);

        if (hm.containsKey(attrName)) {

            // first check if required attribute is other type than string (int, smallint, ...)
            // the convert it to the string
            if (SqlInteger.class.isInstance(hm.get(attrName))) {
                SqlInteger si = ((SqlInteger) hm.get(attrName));
                return "" + si.getValue();
            }
                
            return ((SqlString) hm.get(attrName)).getValue();
        }
           

        return "";
    }

    /* updates string from the current row for AttributeName stated in the function argument */
    public void updateString(String attrName, String value) throws SQLException {

        HashMap hm = values.get(currentRow);

        if (hm.containsKey(attrName)) {

           SqlString s = (SqlString) hm.get(attrName);
           s.setValue(value);
        }

    }



    /* returns date from the current row for AttributeName stated in the function argument */
    public java.sql.Date getDate(String attrName) throws SQLException {

        HashMap hm = values.get(currentRow);

        if (hm.containsKey(attrName)) {

           // first remove time values from date string, leaving only YYYY-MM-DD
           //String tmp = (String) hm.get(attrName);
           //tmp = tmp.substring(0, 10);

           return (java.sql.Date) hm.get(attrName);
        }

        return null;
    }

    /* updates date from the current row for AttributeName stated in the function argument */
    public void updateDate(String attrName, java.util.Date date) throws SQLException {

        HashMap hm = values.get(currentRow);

        if (hm.containsKey(attrName)) {

           // napraviti novu klasu za datum, kao za SqlString, gde moze da se radi get i set

           java.sql.Date sqlDate = (java.sql.Date) hm.get(attrName);
           sqlDate = new java.sql.Date(date.getTime());
        }

    }

    // checks if any of rows in this result set contains unique JMBG value
    public boolean containsJMBG(String jmbg) throws SQLException {

        Enumeration e = values.elements();

        while(e.hasMoreElements()) {

            HashMap hm   = (HashMap) e.nextElement();
            String value = getString("EmployeeJMBG");

            if (value.equals(jmbg))
                return true;
            else
                return false;
        }

        return false;
    }

    /* returns position of current row in the resultset array */
    public int getRow() throws SQLException {

        return currentRow;
    }


    /* removes currently selected row from data array */
    public void deleteRow() {

        values.removeElementAt(currentRow);
    }

    /* inserts new (empty) row in array */
    public void insertRow() {

        HashMap hm = new HashMap();
        hm.put("EmployeeID", new SqlInteger(0));
        hm.put("EmployeeFirstName", new SqlString(""));
        hm.put("EmployeeSurname", new SqlString(""));
        hm.put("EmployeeJMBG", new SqlString(""));
        hm.put("EmployeeDateOfBirth", null);
        hm.put("EmployeeCountryOfBirth", new SqlString(""));
        hm.put("EmployeeStateOfBirth", new SqlString(""));
        hm.put("EmployeeCityOfBirth", new SqlString(""));
        hm.put("EmployeeDistrictOfBirth", new SqlString(""));
        hm.put("EmployeeStreet", new SqlString(""));
        hm.put("EmployeeCountry", new SqlString(""));
        hm.put("EmployeeState", new SqlString(""));
        hm.put("EmployeeDistrict", new SqlString(""));
        hm.put("EmployeeCity", new SqlString(""));
        hm.put("EmployeeWorkingYears", new SqlInteger(0));
        hm.put("EmployeeEducationLevel", new SqlInteger(0));
        hm.put("EmployeeJobDate", null);
        hm.put("EmployeeJobExpirationDate", null);
        hm.put("EmployeeJobStatus", new SqlString(""));
        hm.put("EmployeeJobStatus", new SqlString(""));
        hm.put("EmployeeBLK", new SqlString(""));
        hm.put("EmployeeLBO", new SqlString(""));
        
        values.add(hm);
        // sets the cursor to the latest added row in this vector
        currentRow = values.indexOf(hm);
    }

    /* moves cursor on the next element in the array,
       returns false if end of array is reached, else returnes true
     */
    public boolean next() {

        if (currentRow >= values.size() - 1)
            return false;
        else
            currentRow++;

        return true;
    }

    /* sets cursor before first element in the array */
    public void beforeFirst() {
        currentRow = -1;
    }

    /* checks if cursor is before first element in the array */
    public boolean isBeforeFirst() {
        return (currentRow == -1);
    }

    /* checks if cursor is after last element in the array */
    public boolean isAfterLast() {
        return (currentRow == values.size());
    }

    /* sets cursor after last element in the array */
    public void afterLast() {
        currentRow = values.size();
    }

    /* similar to aboulute method in the ResultSet class */
    public void absolute(int row) {

        if(row >= 0 && row <= values.size())
           currentRow = row;
        else if (row < 0) {
            // example: curentRow = 12 + (-5) = 7
            currentRow = values.size() - Math.abs(row);
            if (currentRow < 0)
              currentRow = -1;
        }
           
        else
           currentRow = -1;
    }


    public int getComponentUniqueID() {

        return _componentUniqueID;
    }

    public void setComponentUniqueID(int id) {

        _componentUniqueID = id;
    }



    public ArrayList<String> getAttributes() {

        return attributes;
    }

    public Vector<HashMap> getValues() {

        return values;
    }

    // lista atributa koji su prisutni u ResultSet
    private ArrayList<String> attributes = new ArrayList<String>();
    // vektor lista. Svaka lista predstavlja jedan red, odnosno ntorku
    private Vector<HashMap> values = new Vector<HashMap>();
    
    private int currentRow = -1;         // cursor which goes through our array (vector) of rows

    /*   represents unique id of some component, which will have several instances
     *   for example, SqlListBox and SqlComboBox which have several instances in application,
     *   so, we must know which component will get its result set
     */
    private int _componentUniqueID = -1;
}
